package TankAgent;

import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.core.AID;
import jade.core.Agent;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.proto.FIPAProtocolNames;
import jade.proto.SimpleAchieveREResponder;

import java.util.Calendar;

import wwtp.ontology.Biological;
import wwtp.ontology.Chemical;
import wwtp.ontology.Hour;
import wwtp.ontology.Origin;
import wwtp.ontology.Physical;
import wwtp.ontology.SendWater;
import wwtp.ontology.Volume;
import wwtp.ontology.WWTPAmazingOntology;
import wwtp.ontology.Water;
import DataBases.DBDirectWater;

public class TankAgent extends Agent{

	protected Codec codec = new SLCodec();
	protected Ontology ontology = WWTPAmazingOntology.getInstance();
	protected double plantCapacity = -1;
	
	protected MessageTemplate mt;
	DBDirectWater dbDirectWater;

	//Propiedades actualPropiedades;
	Chemical chemical;
	Biological biological;
	Physical physical;

	double actualVolumen;
	double maxCapacity;

	boolean mildthunderstormAlarm;

	protected void setup(){

		getContentManager().registerLanguage(codec);
		getContentManager().registerOntology(ontology);

		dbDirectWater = DBDirectWater.getInstance();
	
		mildthunderstormAlarm = false;
		maxCapacity = 200;
		actualVolumen = 0;

		
		chemical = new Chemical();
		chemical.setPercentaje(0);
		biological = new Biological();
		biological.setPercentaje(0);
		physical = new Physical();
		physical.setPercentaje(0);

		addBehaviour(new TankInflowWaterBehaviour());
		addBehaviour(new LaminateBehaviour(this,1000));
		mt = MessageTemplate.and(MessageTemplate.MatchConversationId("ControlFlowProtocol-action"),SimpleAchieveREResponder.createMessageTemplate(FIPAProtocolNames.FIPA_REQUEST));
		addBehaviour(new ControlFlowBehaviour(this, mt));

		System.out.println("Agent created with name: "+getAID().getName());
	}

	@Override
	protected void takeDown() {
		System.out.println("======================> ERASING: "+getAID().getName());
	}


	protected void laminate(double volumen)
	{
		if (volumen > actualVolumen){
			volumen = actualVolumen;
		}
		String destino = dbDirectWater.getLaminateWWTP(this.getLocalName());

		if (destino == null){
			System.out.println(this.getLocalName() + " Sending Water to Authority (River)\n");
			destino = "Authority";
		}
		else{
			System.out.println(this.getLocalName() + " Laminate: "+ volumen + " -> " + destino + "\n");
		}

		SendWater  sw = new SendWater();
		Water 		w = new Water();
		Volume 		v = new Volume();
		Chemical 	c = new Chemical();
		Biological 	b = new Biological();
		Physical 	p = new Physical();

		v.setLitres((float)volumen);
		c.setPercentaje(chemical.getPercentaje());
		b.setPercentaje(biological.getPercentaje());
		p.setPercentaje(physical.getPercentaje());

		w.setVolume(v);
		w.setChemical(c);
		w.setBiological(b);
		w.setPhysical(p);

		sw.setWater(w);

		Hour 	    h = new Hour();
		Calendar date = Calendar.getInstance();
		h.setHours(date.get(Calendar.HOUR_OF_DAY));
		h.setMinutes(date.get(Calendar.MINUTE));
		h.setSeconds(date.get(Calendar.SECOND));
		sw.setHour(h);

		Origin	    o = new Origin();
		o.setName(this.getLocalName());
		sw.setOrigin(o);


		ACLMessage waterMsg = new ACLMessage( ACLMessage.INFORM );
		waterMsg.setConversationId("Water");
		waterMsg.setLanguage(codec.getName());
		waterMsg.setOntology(ontology.getName());

		waterMsg.addReceiver(new AID(destino,AID.ISLOCALNAME));

		try{
			getContentManager().fillContent(waterMsg,sw);
			send(waterMsg);
		}
		catch (Exception e){
			e.printStackTrace();
		}

		actualVolumen -= volumen;
		if (actualVolumen == 0)
		{
			chemical.setPercentaje(0);
			biological.setPercentaje(0);
			physical.setPercentaje(0);
		}
	}

	protected void directSendWater(Water water)
	{
		String destino = dbDirectWater.getLaminateWWTP(this.getLocalName());

		if (destino == null){
			System.out.println(this.getLocalName() + " Sending Water to Authority (River)\n");
			destino = "Authority";
		}
		else{
			System.out.println(this.getLocalName() + " SendWater: "+ water.getVolume().getLitres()  + " -> " + destino+ "\n");
		}
		SendWater  sw = new SendWater();
		sw.setWater(water);
		ACLMessage waterMsg = new ACLMessage( ACLMessage.INFORM );
		waterMsg.setConversationId("Water");
		waterMsg.setLanguage(codec.getName());
		waterMsg.setOntology(ontology.getName());

		Hour 	    h = new Hour();
		Calendar date = Calendar.getInstance();
		h.setHours(date.get(Calendar.HOUR_OF_DAY));
		h.setMinutes(date.get(Calendar.MINUTE));
		h.setSeconds(date.get(Calendar.SECOND));
		sw.setHour(h);

		Origin	    o = new Origin();
		o.setName(this.getLocalName());
		sw.setOrigin(o);

		waterMsg.addReceiver(new AID(destino,AID.ISLOCALNAME));

		try{
			getContentManager().fillContent(waterMsg,sw);
			send(waterMsg);
		}
		catch (Exception e){
			e.printStackTrace();
		}
	}

	protected void bypass(Water water, String destino)
	{
		if (destino == null){
			System.out.println(this.getLocalName() + " Sending Water to Authority (River)\n");
			destino = "Authority";
		}
		else{
			System.out.println(this.getLocalName() + " Bypass: "+ water.getVolume().getLitres()  + " -> " + destino+ "\n");
		}
		SendWater  sw = new SendWater();
		sw.setWater(water);
		ACLMessage waterMsg = new ACLMessage( ACLMessage.INFORM );
		waterMsg.setConversationId("Water");
		waterMsg.setLanguage(codec.getName());
		waterMsg.setOntology(ontology.getName());

		Hour 	    h = new Hour();
		Calendar date = Calendar.getInstance();
		h.setHours(date.get(Calendar.HOUR_OF_DAY));
		h.setMinutes(date.get(Calendar.MINUTE));
		h.setSeconds(date.get(Calendar.SECOND));
		sw.setHour(h);

		Origin	    o = new Origin();
		o.setName(this.getLocalName());
		sw.setOrigin(o);

		waterMsg.addReceiver(new AID(destino,AID.ISLOCALNAME));

		try{
			getContentManager().fillContent(waterMsg,sw);
			send(waterMsg);
		}
		catch (Exception e){
			e.printStackTrace();
		}
	}

	protected void retain(Water water)
	{
		double waterVolume =  water.getVolume().getLitres();
		if (actualVolumen == maxCapacity){
			//Overflow
			System.out.println(this.getLocalName() + " Overflow: " + waterVolume);
			bypass(water, dbDirectWater.getBypassTank(this.getLocalName()));
		}
		else if(actualVolumen + waterVolume < maxCapacity){
			//Retain all
			dissolution(water, waterVolume);
			System.out.println(this.getLocalName() + " Retain: " + waterVolume);
		}
		else{
			//Retain until max Capacity then overflow
			float overflowVolumen = (float) ((actualVolumen + waterVolume) - maxCapacity);
			float retainVolumen = (float) (waterVolume - overflowVolumen);
			dissolution(water, retainVolumen);
			System.out.println(this.getLocalName() + " Retain: " + retainVolumen + " + Overflow: " + overflowVolumen);
			water.getVolume().setLitres((float)overflowVolumen);
			bypass(water, dbDirectWater.getBypassTank(this.getLocalName()));
		}

		System.out.println( this.getLocalName() + " ActualVolumen: " + actualVolumen +" Properties:  C: " + chemical.getPercentaje() + " B: " + biological.getPercentaje() + " P: " + physical.getPercentaje());

	}

	private void dissolution(Water water, double volumen){

		biological.setPercentaje((float)((volumen * water.getBiological().getPercentaje() + actualVolumen * biological.getPercentaje())/(100*(volumen+actualVolumen)))*100);
		chemical.setPercentaje((float)((volumen * water.getChemical().getPercentaje() + actualVolumen * chemical.getPercentaje())/(100*(volumen+actualVolumen)))*100);
		physical.setPercentaje((float)((volumen * water.getPhysical().getPercentaje() + actualVolumen * physical.getPercentaje())/(100*(volumen+actualVolumen)))*100);

		actualVolumen += volumen;
	}
}
